package com.unitd.base.frame.plugin.log.aop;

import com.alibaba.fastjson.JSON;
import com.unitd.base.frame.plugin.log.annotation.Logging;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;


/**
 * 日志注解的具体实现类
 *
 * @author hudan
 * @version 1.0
 * @filename LogAnnoUtil.java
 * @copyright www.unitd.com
 * @date 2020-07-08
 */
@Aspect
@Component
@Slf4j
public class LogAnnoUtil {

    private static Pattern pattern = Pattern.compile("\\{([^\\}]+)\\}");

    /**
     * 切点
     */
    @Pointcut("@annotation(com.unitd.base.frame.plugin.log.annotation.Logging)")
    public void logPointCut() {

    }

    /**
     * 前置通知
     *
     * @param joinPoint 连接点
     */
    @Around("logPointCut()")
    public void saveLog(JoinPoint joinPoint) {
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        // 得到注解的name属性的值
        String desc = method.getAnnotation(Logging.class).name();
        // 过滤掉文本内容,得到{}里的值列表
        desc = descFormat(desc);

        // 获取当前注解切点对应的方法的方法参数名称
        String[] parameterNames = getMethodParameterNames(joinPoint);

        Object[] args = joinPoint.getArgs();
        System.out.println(JSON.toJSONString(args));

        for (String parameterName : parameterNames) {
            // 只针对名称为 datasource 的做处理
            if("datasource".equals(parameterName)) {
                // 暂时只是输出到了控制台，具体需要存库或者存缓存，需要改这段代码
                log.info(desc + "——");
                System.out.println(desc);
            }
        }
    }
//
//    /**
//     * 根据注解记录日志
//     *
//     * @param t          action对象
//     * @param methodName 调用的action方法名称
//     * @param map        参数map
//     */
//    public static <T> void loginfo(T t, String methodName, Map<String, Object> map) {
//        Method[] methods = t.getClass().getDeclaredMethods();
//        for (final Method m : methods) {
//            if (m.getName().equals(methodName)) {
//                if (m.isAnnotationPresent(Logging.class)) {
//                    String desc = m.getAnnotation(Logging.class).description();
//                    List<String> list = descFormat(desc);
//                    for (String s : list) {
//                        String value = map.get(s).toString();
//                        desc = desc.replace("{" + s + "}", value);
//                    }
//                    // 暂时只是输出到了控制台，具体需要存库或者存缓存，需要改这段代码
//                    log.info(desc);
//                    System.out.println(desc);
//                }
//            }
//        }
//    }

    /**
     * 获取日志信息中的动态参数，然后替换
     *
     * @param desc 具体日志详情
     * @return 使用日志注解的原参数
     */
    private static String descFormat(String desc) {
        List<String> list = new ArrayList<>();
        Matcher matcher = pattern.matcher(desc);
        while (matcher.find()) {
            return matcher.group(1);
        }
        return null;
    }

    /**
     * 获取当前注解切点对应的方法的方法参数名称
     *
     * @param joinPoint 当前切点
     * @return 请求方法的方法参数名称
     */
    private String[] getMethodParameterNames(JoinPoint joinPoint) {

        // 拦截的放参数类型
        Signature sig = joinPoint.getSignature();
        if (!(sig instanceof MethodSignature)) {
            throw new IllegalArgumentException("该注解只能用于方法");
        }
        MethodSignature msig = (MethodSignature) sig;
        return msig.getParameterNames();
    }

    public static void main(String[] args) {
        System.out.println(JSON.toJSONString(descFormat("{datasource}")));
        ;
    }
}